package com.doubao.hardware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.doubao.hardware.dto.DeviceRegistrationDTO;
import com.doubao.hardware.entity.HardwareDeviceEntity;
import com.doubao.hardware.mapper.HardwareDeviceMapper;
import com.doubao.hardware.service.DeviceRegistrationService;
import com.doubao.hardware.service.MqttService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 * 设备注册服务实现类
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class DeviceRegistrationServiceImpl implements DeviceRegistrationService {

    private final HardwareDeviceMapper hardwareDeviceMapper;
    private final MqttService mqttService;

    @Value("${hardware.config.default-status:1}")
    private Integer defaultStatus;

    @Value("${mqtt.baidu.topic:$iot/Albot_Config/user/ai}")
    private String baiduTopic;

    @Override
    @Transactional
    public HardwareDeviceEntity registerDevice(DeviceRegistrationDTO registrationDTO) {
        // 验证参数
        if (registrationDTO.getProductId() == null || registrationDTO.getProductId().isEmpty()) {
            throw new RuntimeException("产品ID不能为空");
        }

        if (registrationDTO.getMacAddress() == null || registrationDTO.getMacAddress().isEmpty()) {
            throw new RuntimeException("MAC地址不能为空");
        }

        log.info("开始注册设备: {}, 产品ID: {}", registrationDTO.getMacAddress(), registrationDTO.getProductId());

        // 规范化MAC地址格式
        String macAddress = formatMacAddress(registrationDTO.getMacAddress());
        registrationDTO.setMacAddress(macAddress);

        // 如果未提供用户ID，尝试从请求中获取
        if (registrationDTO.getUserId() == null) {
            Long currentUserId = getCurrentUserId();
            if (currentUserId != null) {
                registrationDTO.setUserId(currentUserId);
                log.info("从请求头获取到用户ID: {}", currentUserId);
            }
        }

        // 检查设备是否已存在
        HardwareDeviceEntity existingDevice = hardwareDeviceMapper.selectByMacAddress(macAddress);

        if (existingDevice != null) {
            // 详细检查设备绑定状态
            if (existingDevice.getUserId() != null &&
                    registrationDTO.getUserId() != null &&
                    !existingDevice.getUserId().equals(registrationDTO.getUserId())) {

                log.warn("设备 {} 已被用户 {} 绑定，当前用户 {} 尝试注册",
                        macAddress, existingDevice.getUserId(), registrationDTO.getUserId());

                // 抛出更具体的异常
                throw new DeviceAlreadyBoundException(
                        "设备已被用户ID为 " + existingDevice.getUserId() + " 的用户绑定"
                );
            }

            // 如果是同一个用户或未绑定，执行更新
            return updateExistingDevice(existingDevice, registrationDTO);
        }

        // 设备不存在，创建新设备
        return createNewDevice(macAddress.replaceAll("[:-]", "").toUpperCase(), registrationDTO);
    }

    // 自定义异常，详细描述设备绑定情况
    public static class DeviceAlreadyBoundException extends RuntimeException {
        private Long boundUserId;

        public DeviceAlreadyBoundException(String message) {
            super(message);
            // 尝试从错误消息中提取用户ID
            try {
                boundUserId = Long.parseLong(message.replaceAll("\\D", ""));
            } catch (NumberFormatException e) {
                boundUserId = null;
            }
        }

        public Long getBoundUserId() {
            return boundUserId;
        }
    }

    /**
     * 格式化MAC地址，确保使用冒号分隔且全小写
     */
    private String formatMacAddress(String macAddress) {
        if (macAddress == null) {
            return "";
        }

        // 移除所有分隔符
        String mac = macAddress.replaceAll("[:-]", "").toLowerCase();

        // 如果已经是规范格式，直接返回
        if (macAddress.contains(":") && macAddress.length() == 17) {
            return macAddress.toLowerCase();
        }

        // 插入冒号
        StringBuilder formattedMac = new StringBuilder();
        for (int i = 0; i < mac.length(); i++) {
            if (i > 0 && i % 2 == 0) {
                formattedMac.append(':');
            }
            formattedMac.append(mac.charAt(i));
        }

        return formattedMac.toString();
    }
    /**
     * 更新已存在的设备
     */
    private HardwareDeviceEntity updateExistingDevice(HardwareDeviceEntity existingDevice, DeviceRegistrationDTO registrationDTO) {
        try {
            // 更新设备信息
            existingDevice.setIpAddress(registrationDTO.getIpAddress());
            existingDevice.setIsOnline(1); // 设置为在线状态
            existingDevice.setLastOnlineTime(LocalDateTime.now());
            existingDevice.setProductId(registrationDTO.getProductId());

            if (registrationDTO.getFirmwareVersion() != null) {
                existingDevice.setFirmwareVersion(registrationDTO.getFirmwareVersion());
            }

            // 如果传入了用户ID并且设备尚未绑定或已绑定的用户ID不同，更新用户ID
            if (registrationDTO.getUserId() != null &&
                    (existingDevice.getUserId() == null || !existingDevice.getUserId().equals(registrationDTO.getUserId()))) {
                existingDevice.setUserId(registrationDTO.getUserId());
                log.info("设备绑定到新用户: {}", registrationDTO.getUserId());
            }

            // 如果传入了设备昵称，更新设备昵称
            if (registrationDTO.getNickname() != null) {
                existingDevice.setNickname(registrationDTO.getNickname());
            }

            // 如果传入了WiFi信息，更新扩展JSON
            if (registrationDTO.getWifiSsid() != null || registrationDTO.getWifiSignal() != null) {
                // 构建扩展信息JSON
                String extJson = "{"
                        + "\"wifiSsid\":\"" + (registrationDTO.getWifiSsid() != null ? registrationDTO.getWifiSsid() : "") + "\","
                        + "\"wifiSignal\":" + (registrationDTO.getWifiSignal() != null ? registrationDTO.getWifiSignal() : 0) + ","
                        + "\"lastUpdateTime\":\"" + LocalDateTime.now() + "\","
                        + "\"updateId\":\"" + UUID.randomUUID().toString().substring(0, 8) + "\""
                        + "}";

                existingDevice.setExtJson(extJson);
            }

            // 更新时间字段
            existingDevice.setUpdatedAt(LocalDateTime.now());

            // 执行数据库更新
            hardwareDeviceMapper.updateById(existingDevice);

            // 发送设备上线通知(捕获异常不影响主流程)
            try {
                sendDeviceStatusUpdate(existingDevice.getId(), existingDevice.getDeviceSn(), true);
            } catch (Exception e) {
                log.warn("发送设备状态通知失败，但设备更新成功: {}", e.getMessage());
            }

            return existingDevice;
        } catch (Exception e) {
            log.error("更新设备失败: {}", e.getMessage(), e);
            throw new RuntimeException("更新设备失败: " + e.getMessage(), e);
        }
    }

    /**
     * 创建新设备
     */
    private HardwareDeviceEntity createNewDevice(String deviceSn, DeviceRegistrationDTO registrationDTO) {
        try {
            // 创建新设备
            HardwareDeviceEntity newDevice = new HardwareDeviceEntity();
            newDevice.setDeviceSn(deviceSn);
            newDevice.setMacAddress(registrationDTO.getMacAddress());
            newDevice.setProductId(registrationDTO.getProductId());
            newDevice.setUserId(registrationDTO.getUserId());

            // 设置昵称
            String nickname = registrationDTO.getNickname();
            if (nickname == null || nickname.isEmpty()) {
                // 如果MAC地址长度够，则使用末尾几位作为昵称后缀
                String macSuffix = registrationDTO.getMacAddress().length() > 9
                        ? registrationDTO.getMacAddress().substring(registrationDTO.getMacAddress().length() - 8)
                        : registrationDTO.getMacAddress();
                newDevice.setNickname("新设备-" + macSuffix);
            } else {
                newDevice.setNickname(nickname);
            }

            newDevice.setFirmwareVersion(registrationDTO.getFirmwareVersion());
            newDevice.setIpAddress(registrationDTO.getIpAddress());
            newDevice.setIsOnline(1); // 设置为在线状态
            newDevice.setLastOnlineTime(LocalDateTime.now());
            newDevice.setStatus(defaultStatus); // 使用配置的默认状态

            // 构建扩展信息JSON
            String extJson = "{"
                    + "\"wifiSsid\":\"" + (registrationDTO.getWifiSsid() != null ? registrationDTO.getWifiSsid() : "") + "\","
                    + "\"wifiSignal\":" + (registrationDTO.getWifiSignal() != null ? registrationDTO.getWifiSignal() : 0) + ","
                    + "\"registerTime\":\"" + LocalDateTime.now() + "\","
                    + "\"deviceId\":\"" + UUID.randomUUID().toString().substring(0, 8) + "\""
                    + "}";

            newDevice.setExtJson(extJson);

            // 设置创建和更新时间字段 - 解决数据库插入错误
            newDevice.setCreatedAt(LocalDateTime.now());
            newDevice.setUpdatedAt(LocalDateTime.now());

            // 插入新设备记录
            hardwareDeviceMapper.insert(newDevice);

            // 发送设备上线通知(捕获异常不影响主流程)
            try {
                sendDeviceStatusUpdate(newDevice.getId(), newDevice.getDeviceSn(), true);
            } catch (Exception e) {
                log.warn("发送设备状态通知失败，但设备创建成功: {}", e.getMessage());
            }

            return newDevice;
        } catch (Exception e) {
            log.error("创建新设备失败: {}", e.getMessage(), e);
            throw new RuntimeException("创建新设备失败: " + e.getMessage(), e);
        }
    }

    @Override
    public boolean isDeviceRegistered(String macAddress) {
        if (macAddress == null || macAddress.isEmpty()) {
            return false;
        }

        try {
            HardwareDeviceEntity device = hardwareDeviceMapper.selectByMacAddress(macAddress);
            return device != null;
        } catch (Exception e) {
            log.error("查询设备注册状态失败: {}", e.getMessage());
            return false;
        }
    }

    @Override
    @Transactional
    public void bindDeviceToUser(Long deviceId, Long userId) {
        log.info("绑定设备 {} 到用户 {}", deviceId, userId);

        // 检查设备是否存在
        HardwareDeviceEntity device = hardwareDeviceMapper.selectById(deviceId);
        if (device == null) {
            throw new RuntimeException("设备不存在，ID: " + deviceId);
        }

        // 更新设备所属用户
        hardwareDeviceMapper.bindToUser(deviceId, userId);

        // 发送设备绑定通知
        String topic = "doubao/hardware/binding/" + device.getDeviceSn();
        String payload = "{\"userId\":" + userId + ", \"time\":\"" + LocalDateTime.now() + "\"}";

        try {
            mqttService.sendMessageToTopic(topic, payload);
            log.info("已发送设备绑定通知");

            // 同时发送到百度云物联网平台
            if (baiduTopic != null && !baiduTopic.isEmpty()) {
                String baiduPayload = "{\"type\":\"binding\",\"deviceId\":\"" + deviceId +
                        "\",\"deviceSn\":\"" + device.getDeviceSn() +
                        "\",\"userId\":" + userId +
                        ",\"time\":\"" + LocalDateTime.now() + "\"}";
                mqttService.sendMessageToTopic(baiduTopic, baiduPayload);
                log.info("已发送设备绑定通知到百度云平台");
            }
        } catch (Exception e) {
            log.error("发送设备绑定通知失败: {}", e.getMessage());
            // 不影响主流程，继续执行
        }
    }

    @Override
    @Transactional
    public void unbindDevice(Long deviceId) {
        log.info("解绑设备: {}", deviceId);

        // 检查设备是否存在
        HardwareDeviceEntity device = hardwareDeviceMapper.selectById(deviceId);
        if (device == null) {
            throw new RuntimeException("设备不存在，ID: " + deviceId);
        }

        // 更新设备，解除用户绑定
        hardwareDeviceMapper.unbindDevice(deviceId);

        // 发送设备解绑通知
        String topic = "doubao/hardware/binding/" + device.getDeviceSn();
        String payload = "{\"userId\":null, \"time\":\"" + LocalDateTime.now() + "\"}";

        try {
            mqttService.sendMessageToTopic(topic, payload);
            log.info("已发送设备解绑通知");

            // 同时发送到百度云物联网平台
            if (baiduTopic != null && !baiduTopic.isEmpty()) {
                String baiduPayload = "{\"type\":\"unbinding\",\"deviceId\":\"" + deviceId +
                        "\",\"deviceSn\":\"" + device.getDeviceSn() +
                        "\",\"time\":\"" + LocalDateTime.now() + "\"}";
                mqttService.sendMessageToTopic(baiduTopic, baiduPayload);
                log.info("已发送设备解绑通知到百度云平台");
            }
        } catch (Exception e) {
            log.error("发送设备解绑通知失败: {}", e.getMessage());
            // 不影响主流程，继续执行
        }
    }

    @Override
    public void updateDeviceOnlineStatus(Long deviceId, boolean isOnline) {
        log.info("更新设备在线状态: {}, 状态: {}", deviceId, isOnline);

        // 检查设备是否存在
        HardwareDeviceEntity device = hardwareDeviceMapper.selectById(deviceId);
        if (device == null) {
            throw new RuntimeException("设备不存在，ID: " + deviceId);
        }

        // 更新在线状态
        hardwareDeviceMapper.updateOnlineStatus(deviceId, isOnline ? 1 : 0);

        // 发送设备状态更新通知
        sendDeviceStatusUpdate(deviceId, device.getDeviceSn(), isOnline);
    }

    /**
     * 发送设备状态更新通知
     * @param deviceId 设备ID
     * @param deviceSn 设备序列号
     * @param isOnline 是否在线
     */
    private void sendDeviceStatusUpdate(Long deviceId, String deviceSn, boolean isOnline) {
        try {
            // 首先尝试发送到百度云物联网平台
            if (baiduTopic != null && !baiduTopic.isEmpty()) {
                String baiduPayload = "{\"deviceId\":\"" + deviceId +
                        "\",\"deviceSn\":\"" + deviceSn +
                        "\",\"status\":\"" + (isOnline ? "online" : "offline") +
                        "\",\"time\":\"" + LocalDateTime.now() + "\"}";
                mqttService.sendMessageToTopic(baiduTopic, baiduPayload);
                log.info("已发送设备状态到百度云物联网平台: {}, 状态: {}", deviceSn, isOnline ? "online" : "offline");
            }

            // 然后发送到本地主题
            String topic = "doubao/hardware/device/" + deviceSn + "/status";
            String payload = isOnline ? "online" : "offline";
            mqttService.sendMessageToTopic(topic, payload);
            log.info("已发送设备状态更新通知: {}, 状态: {}", deviceSn, payload);
        } catch (Exception e) {
            // 仅记录错误，不抛出异常
            log.error("发送设备状态更新通知失败: {}", e.getMessage());
        }
    }

    /**
     * 从请求头中获取当前用户ID
     * 兼容不同的认证方式
     */
    private Long getCurrentUserId() {
        try {
            // 获取当前请求
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return null;
            }

            HttpServletRequest request = attributes.getRequest();

            // 尝试从X-User-ID头获取用户ID
            String userIdHeader = request.getHeader("X-User-ID");
            if (userIdHeader != null && !userIdHeader.isEmpty()) {
                try {
                    return Long.valueOf(userIdHeader);
                } catch (NumberFormatException e) {
                    log.warn("无法解析X-User-ID头: {}", userIdHeader);
                }
            }

            // 尝试从Authorization头获取Bearer Token
            String authHeader = request.getHeader("Authorization");
            if (authHeader != null && authHeader.startsWith("Bearer ")) {
                // 在实际应用中，这里应该解析JWT Token获取用户ID
                log.debug("检测到Bearer Token，但未实现JWT解析");
            }

            return null;
        } catch (Exception e) {
            log.error("获取当前用户ID失败: {}", e.getMessage());
            return null;
        }
    }
}